using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Controls;
using Microsoft.VisualStudio.TeamFoundation.WorkItemTracking;
using System.Collections.Specialized;

namespace WitCustomControls
{
	public partial class WorkItemHierarchy : UserControl, IWorkItemControl
	{
		const string c_parentWorkItemFieldName = "ParentWorkItem";

		string m_originalState = string.Empty;
		string m_originalAssignedTo = string.Empty;
		bool m_isSettingFieldsManually = false;

		public WorkItemHierarchy()
		{
			InitializeComponent();

			this.Dock = System.Windows.Forms.DockStyle.Fill;
			this.Anchor = System.Windows.Forms.AnchorStyles.Top |
										System.Windows.Forms.AnchorStyles.Right |
										System.Windows.Forms.AnchorStyles.Bottom |
										System.Windows.Forms.AnchorStyles.Left;
		}

		private void AddEventHandler()
		{
			if (m_workItem != null && m_workItem.Id != 0 && m_workItem.State != "Closed")
			{
				m_workItem.FieldChanged += new WorkItemFieldChangeEventHandler(this.workItem_FieldChanged);
				m_originalState = m_workItem.Fields["State"].Value.ToString();
				m_originalAssignedTo = m_workItem.Fields["Assigned To"].Value.ToString();
			}
		}

		private void workItem_FieldChanged(object sender, WorkItemEventArgs e)
		{
			//Test to see if the user is closing a work item
			if (!this.IsDisposed && e.Field != null)
			{
				if (m_isSettingFieldsManually == false && (e.Field.Name == "Assigned To" || (e.Field.Name == "State" && e.Field.Value.ToString() != "Closed")))
				{
					m_originalState = m_workItem.Fields["State"].Value.ToString();
					m_originalAssignedTo = m_workItem.Fields["Assigned To"].Value.ToString();
				}

				if (e.Field.Name == "State" && e.Field.OriginalValue.ToString() != "Closed" && e.Field.Value.ToString() == "Closed")
				{
					if (IsChildOpen(m_workItem) == true)
					{
						MessageBox.Show("Work Items cannot be closed until all child Work Items are closed.", "Hierarchy error");

						System.Threading.Thread resetThread = new System.Threading.Thread(new System.Threading.ThreadStart(ResetState));
						resetThread.Start();
					}
				}
			}
		}

		private void ResetState()
		{
			m_isSettingFieldsManually = true;
			m_workItem.State = m_originalState;
			m_workItem.Fields["Assigned To"].Value = m_originalAssignedTo;
			m_isSettingFieldsManually = false;
		}

		private bool IsChildOpen(WorkItem parentWorkItem)
		{
			if (parentWorkItem != null && parentWorkItem.Id != 0)
			{
				WorkItemCollection children = m_workItem.Store.Query("SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '" + parentWorkItem.Project.Name + "' AND [" + c_parentWorkItemFieldName + "] = " + parentWorkItem.Id.ToString());
				if (children.Count > 0)
				{
					foreach (WorkItem wi in children)
					{
						if (wi.State != "Closed")
						{
							return true;
						}

						//recurse children
						if (IsChildOpen(wi) == true)
						{
							return true;
						}
					}

					return false;
				}
			}

			return false;
		}

		private void workItemTreeView_AfterSelect(object sender, TreeViewEventArgs e)
		{
			if (e.Node != null && e.Node != this.workItemTreeView.Nodes[0] && e.Node.Text != "No work items")
			{
				WorkItem clickedWorkItem = (WorkItem)e.Node.Tag;

				// Use ServiceProvider to get documentservice and open work item
				DocumentService ds = (DocumentService)m_serviceProvider.GetService(typeof(DocumentService));
				IWorkItemDocument doc = ds.GetWorkItem(clickedWorkItem.Store.TeamFoundationServer, clickedWorkItem.Id, this);

				try
				{
					ds.ShowWorkItem(doc);
				}
				finally
				{
					doc.Release(this);
					this.workItemTreeView.SelectedNode = this.workItemTreeView.Nodes[0];
				}
			}
		}

		#region IWorkItemControl Members

		private EventHandlerList m_events;

		private EventHandlerList Events
		{
			get
			{
				if (m_events == null)
				{
					m_events = new EventHandlerList();
				}
				return m_events;
			}
		}

		private static object EventBeforeUpdateDatasource = new object();
		private static object EventAfterUpdateDatasource = new object();
		event EventHandler IWorkItemControl.BeforeUpdateDatasource
		{
			add
			{
				Events.AddHandler(EventBeforeUpdateDatasource, value);
			}
			remove
			{
				Events.RemoveHandler(EventBeforeUpdateDatasource, value);
			}
		}
		event EventHandler IWorkItemControl.AfterUpdateDatasource
		{
			add
			{
				Events.AddHandler(EventAfterUpdateDatasource, value);
			}
			remove
			{
				Events.RemoveHandler(EventAfterUpdateDatasource, value);
			}
		}

		protected virtual void OnBeforeUpdateDatasource(EventArgs eventArgs)
		{
			EventHandler handler = (EventHandler)Events[EventBeforeUpdateDatasource];
			if (handler != null)
			{
				handler.Invoke(this, eventArgs);
			}
		}

		protected virtual void OnAfterUpdateDatasource(EventArgs eventArgs)
		{
			EventHandler handler = (EventHandler)Events[EventAfterUpdateDatasource];
			if (handler != null)
			{
				handler.Invoke(this, eventArgs);
			}
		}

		void IWorkItemControl.Clear()
		{
			workItemTreeView.Nodes.Clear();
		}

		void IWorkItemControl.FlushToDatasource()
		{
			// nothing to do
		}

		void IWorkItemControl.InvalidateDatasource()
		{
			this.workItemTreeView.Nodes.Clear();

			if (m_workItem != null && m_workItem.Id != 0)
			{
				TreeNode rootNode = new TreeNode(m_workItem.Type.Name + " " + m_workItem.Id.ToString());
				rootNode.ToolTipText = m_workItem.Title;
				rootNode.ImageKey = "workItem_" + m_workItem.Type.Name.Replace(" ", "");
				rootNode.SelectedImageKey = "workItem_" + m_workItem.Type.Name.Replace(" ", "");
				this.workItemTreeView.Nodes.Add(rootNode);

				WorkItemCollection items = m_workItem.Store.Query("SELECT [System.Id], [System.WorkItemType], [System.State], [System.Title] FROM WorkItems WHERE [System.TeamProject] = '" + m_workItem.Project.Name + "' AND [" + c_parentWorkItemFieldName + "] = " + m_workItem.Id.ToString() + " ORDER BY [System.WorkItemType], [System.Id]");
				if (items.Count > 0)
				{
					AddChildNodes(rootNode, m_workItem);
				}
				else
				{
					TreeNode emptyNode = new TreeNode("No work items");
					emptyNode.ImageKey = "workItem";
					emptyNode.SelectedImageKey = "workItem";
					emptyNode.ForeColor = Color.Gray;
					rootNode.Nodes.Add(emptyNode);
				}
			}

			this.workItemTreeView.ExpandAll();
		}

		private void AddChildNodes(TreeNode parentNode, WorkItem parentWorkItem)
		{
			WorkItemStore store = parentWorkItem.Store;
			WorkItemCollection items = store.Query("SELECT [System.Id], [System.WorkItemType], [System.State], [System.Title] FROM WorkItems WHERE [System.TeamProject] = '" + parentWorkItem.Project.Name + "' AND [" + c_parentWorkItemFieldName + "] = " + parentWorkItem.Id.ToString() + " ORDER BY [System.WorkItemType], [System.Id]");

			if (items.Count > 0)
			{
				foreach (WorkItem childWorkItem in items)
				{
					//Add Child Node to the TreeView
					TreeNode node = new TreeNode(childWorkItem.Type.Name + " " + childWorkItem.Id.ToString() + " - " + childWorkItem.State + ", " + childWorkItem.Reason);
					node.ImageKey = "workItem_" + childWorkItem.Type.Name.Replace(" ", "");
					node.SelectedImageKey = "workItem_" + childWorkItem.Type.Name.Replace(" ", "");
					node.Tag = childWorkItem;

					parentNode.Nodes.Add(node);

					//Repeat for all children of this child
					AddChildNodes(node, childWorkItem);
				}
			}
		}

		private StringDictionary m_properties;
		StringDictionary IWorkItemControl.Properties
		{
			get
			{
				return m_properties;
			}
			set
			{
				m_properties = value;
			}
		}

		private bool m_readOnly;
		bool IWorkItemControl.ReadOnly
		{
			get
			{
				return m_readOnly;
			}
			set
			{
				m_readOnly = value;
			}
		}

		private IServiceProvider m_serviceProvider;
		void IWorkItemControl.SetSite(IServiceProvider serviceProvider)
		{
			m_serviceProvider = serviceProvider;
		}

		private WorkItem m_workItem;
		object IWorkItemControl.WorkItemDatasource
		{
			get
			{
				return m_workItem;
			}
			set
			{
				m_workItem = (WorkItem)value;
				AddEventHandler();
			}
		}

		private string m_fieldName;
		string IWorkItemControl.WorkItemFieldName
		{
			get
			{
				return m_fieldName;
			}
			set
			{
				m_fieldName = value;
			}
		}

		#endregion

		private bool m_isDirty;
		public bool IsDirty
		{
			get
			{
				return m_isDirty;
			}
			set
			{
				m_isDirty = value;
			}
		}
	}
}
